package ru.usu.gv.utils;

import ru.usu.gv.graph.Graph;
import ru.usu.gv.graph.Vertex;

import javax.vecmath.Point3d;

import java.util.Random;

/**
 @author: Sergey Pupyrev 
 Mar 26, 2006
 */

public class RandomUtilities
{
	private static Random random = new Random(123);

	//for test purposes only!!
	public static void setSeed(int seed)
	{
		random.setSeed(seed);
	}

	public static double nextDouble()
	{
		return random.nextDouble();
	}

	public static int nextInt()
	{
		return random.nextInt();
	}

	public static int nextInt(int upper)
	{
		return random.nextInt(upper);
	}

	public static Point3d generateRandomPoint()
	{
		double a = -1d;
		double b = 2d;

		return new Point3d(a + b * random.nextDouble(), a + b * random.nextDouble(), a + b * random.nextDouble());
	}

	public static Graph generateGrid3d(int n, int m, int k)
	{
		Graph graph = new Graph();
		for (int i = 0; i <= n; i++)
			for (int j = 0; j <= m; j++)
				for (int r = 0; r <= k; r++)
				{
					graph.addVertex(new Vertex());
				}

		for (int i = 0; i <= n; i++)
			for (int j = 0; j <= m; j++)
				for (int r = 0; r <= k; r++)
				{
					Vertex v = graph.getVertex(i * (m + 1) * (k + 1) + j * (k + 1) + r);
					if (i - 1 >= 0)
					{
						Vertex u = graph.getVertex((i - 1) * (m + 1) * (k + 1) + j * (k + 1) + r);
						graph.addEdge(v, u);
					}
					if (j - 1 >= 0)
					{
						Vertex u = graph.getVertex(i * (m + 1) * (k + 1) + (j - 1) * (k + 1) + r);
						graph.addEdge(v, u);
					}
					if (r - 1 >= 0)
					{
						Vertex u = graph.getVertex(i * (m + 1) * (k + 1) + j * (k + 1) + r - 1);
						graph.addEdge(v, u);
					}
				}

		return graph;
	}

	public static Graph generateGrid2d(int n, int m)
	{
		Graph graph = new Graph();
		for (int i = 0; i <= n; i++)
			for (int j = 0; j <= m; j++)
			{
				Vertex v = new Vertex();
				graph.addVertex(v);
			}

		for (int i = 0; i <= n; i++)
			for (int j = 0; j <= m; j++)
			{
				Vertex v = graph.getVertex(i * (m + 1) + j);
				if (i - 1 >= 0)
				{
					Vertex u = graph.getVertex((i - 1) * (m + 1) + j);
					graph.addEdge(v, u);
				}

				if (j - 1 >= 0)
				{
					Vertex u = graph.getVertex(i * (m + 1) + j - 1);
					graph.addEdge(v, u);
				}
			}

		//addEdge(graph, graph.getVertex(0), graph.getVertex((n + 1) * (m + 1) - 1));
		return graph;
	}

	public static Graph generateRandomTree(int nodesCount)
	{
		Graph graph = new Graph();
		int n = nodesCount;

		for (int i = 0; i < n; i++)
		{
			Vertex v = new Vertex();
			graph.addVertex(v);
		}

		for (int i = 1; i < n; i++)
		{
			Vertex v1 = graph.getVertex(i);
			int k = random.nextInt(i);
			Vertex v2 = graph.getVertex(k);

			graph.addEdge(v1, v2);
		}

		return graph;
	}

	public static Graph generateRandomGraph(int vCount, double eFreq)
	{
		Graph graph = new Graph();
		int n = vCount;

		for (int i = 0; i < n; i++)
		{
			Vertex v = new Vertex();
			graph.addVertex(v);
		}

		for (int i = 0; i < n; i++)
			for (int j = i + 1; j < n; j++)
				if (random.nextDouble() < eFreq)
				{
					Vertex v1 = graph.getVertex(i);
					Vertex v2 = graph.getVertex(j);

					graph.addEdge(v1, v2);
				}

		return graph;
	}

	public static Graph generateMebGraph(int k1, int k2)
	{
		Graph graph = new Graph();
		int n = k1 * k2;

		for (int i = 0; i < n; i++)
		{
			Vertex v = new Vertex();
			graph.addVertex(v);
		}

		for (int i = 0; i < k2; i++)
		{
			for (int j = 0; j < k1 - 1; j++)
			{
				Vertex v1 = graph.getVertex(i * k1 + j);
				Vertex v2 = graph.getVertex(i * k1 + (j + 1));

				graph.addEdge(v1, v2);
			}
		}

		for (int i = 0; i < k1; i++)
		{
			for (int j = 0; j < k2 - 1; j++)
			{
				Vertex v1 = graph.getVertex(j * k1 + i);
				Vertex v2 = graph.getVertex((j + 1) * k1 + i);

				graph.addEdge(v1, v2);
			}

			Vertex v1 = graph.getVertex((k2 - 1) * k1 + i);
			Vertex v2 = graph.getVertex(0 * k1 + k1 - i - 1);

			graph.addEdge(v1, v2);
		}

		return graph;
	}

	public static Graph generateBinaryTree(int depth)
	{
		if (depth > 15)
		{
			System.err.println("Too many vertexes");
			return new Graph();
		}

		Graph graph = new Graph();
		int n = (1 << depth);

		for (int i = 0; i < n; i++)
		{
			Vertex v = new Vertex();
			graph.addVertex(v);
		}

		for (int i = 0; i < n; i++)
		{
			int l = 2 * (i + 1) - 1;
			int r = 2 * (i + 1);

			if (l < n)
			{
				Vertex v1 = graph.getVertex(i);
				Vertex v2 = graph.getVertex(l);

				graph.addEdge(v1, v2);
			}
			if (r < n)
			{
				Vertex v1 = graph.getVertex(i);
				Vertex v2 = graph.getVertex(r);

				graph.addEdge(v1, v2);
			}
		}

		return graph;
	}

	public static int randIndex(double[] probs)
	{
		double p = nextDouble();
		double tec = 0;
		for (int i = 0; i < probs.length; i++)
		{
			tec += probs[i];
			if (tec >= p)
				return i;
		}

		assert (false);
		return -1;
	}
}
